package utils

import (
	"fmt"
	"os"
	"os/signal"
	"regexp"
	"sort"
	"strings"
	"syscall"
	"time"

	"qkcoupon/errorcode"
	"qkcoupon/models"
	"qkcoupon/rpc/client/qingke"

	"doubimeizhi.com/utility"
	log "github.com/cihub/seelog"
)

/*
 *@note 洗衣房编号或洗衣机编号是否存在
 *@return bool, false:不存在，true:存在
 */
func IsExistRwid(rid string, wid string, rwids *models.PCQkCouponRwids) bool {
	if rwids == nil {
		return true
	}

	if len(rwids.List) == 0 {
		return true
	}

	var exist = false

	for _, rwid := range rwids.List {
		if rwid.Rid == rid {
			if len(rwid.Wids) == 0 {
				exist = true
				break
			}

			for _, id := range rwid.Wids {
				if id == wid {
					exist = true
					break
				}
			}
		}
	}

	return exist
}

/*
 *@note 处理信号
 */
func HandleSignals() {
	sigChan := make(chan os.Signal)
	signal.Notify(
		sigChan,
		syscall.SIGHUP,
	)

	<-sigChan

	pid := syscall.Getpid()
	log.Errorf("pid: %d, Received SIGHUP.", pid)

	log.Error("Server quit!")
	log.Current.Flush()

	if process, err := os.FindProcess(pid); err == nil {
		process.Kill()
	}
}

/*
 *@note 检测优惠劵类型
 *@param ctype: 优惠劵类型
 *@return bool, false:不在范围内，true:在范围内
 */
func CheckCType(ctype int32) bool {
	if ctype == int32(models.EQKCOUPON_CTYPE_NULL1) {
		return false
	}

	_, ok := models.EQKCOUPON_CTYPE_name[ctype]
	if !ok {
		return false
	}

	return true
}

/*
 *@note 检测优惠劵状态
 *@param cstate: 优惠劵状态
 *@return bool, false:不在范围内，true:在范围内
 */
func CheckCState(cstate int32) bool {
	if cstate == int32(models.EQKCOUPON_CSTATE_NULL2) {
		return false
	}

	_, ok := models.EQKCOUPON_CSTATE_name[cstate]
	if !ok {
		return false
	}

	return true
}

/*
 *@note 检测用户类型
 *@param utype: 用户类型
 *@return bool, false:不在范围内，true:在范围内
 */
func CheckUType(utype int32) bool {
	_, ok := models.EQKCOUPON_UTYPE_name[utype]
	if !ok {
		return false
	}

	return true
}

/*
 *@note 检测洗衣模式
 *@param washMode: 洗衣模式
 *@return bool, false:不在范围内，true:在范围内
 */
func CheckWashMode(washMode int32) bool {
	_, ok := models.EQK_WASH_MODE_name[washMode]
	if !ok {
		return false
	}

	return true
}

/*
 *@note 检测操作类型
 *@param operationType: 操作类型
 *@return bool, false:不在范围内，true:在范围内
 */
func CheckOperationType(operationType int32) bool {
	if operationType == int32(models.EQKCOUPON_OPERATE_TYPE_NULL3) {
		return false
	}

	_, ok := models.EQKCOUPON_OPERATE_TYPE_name[operationType]
	if !ok {
		return false
	}

	return true
}

/*
 *@note 获取使用的范围内容
 *@param rwids: PCQkCouponRwids
 *@return string: 范围内容
 */
func GetUseRange(rwids *models.PCQkCouponRwids, token string, uid string) string {

	return "全部洗衣点可用"

	if rwids == nil {
		return "全部洗衣点可用"
	}
	if len(rwids.List) == 0 {
		return "全部洗衣点可用"
	}
	rids := make([]string, 0)
	for _, rinfo := range rwids.List {
		rids = append(rids, rinfo.Rid)
	}
	infos, err := qingke.GetRoomInfo(rids, token, uid)
	if err != errorcode.EC_GL_SUCCESS {
		return "查询洗衣点信息异常"
	}
	result := ""
	for _, info := range infos {
		result += info.RoomName
		result += ":"
		for _, rwinfo := range rwids.List {
			for _, wid := range rwinfo.Wids {
				result += wid
				result += "、"
			}
		}
		tmp := []rune(result)
		tmp = tmp[:len(tmp)-1]
		result = string(tmp)
		result += "，"
	}
	tmp := []rune(result)
	tmp = tmp[:len(tmp)-1]
	result = string(tmp)
	result += "可用"
	log.Debugf("洗衣房信息：%s", result)
	return result
}

/*
 *@note 获取排序后的时间范围列表
 *@param timeRange: PCQkCouponTimeRanges
 *@return []int: 排序后的时间列表
 */
func getSortTimeRangeList(timeRange *models.PCQkCouponTimeRanges) []int {
	if timeRange == nil {
		return nil
	}

	dl := len(timeRange.Date)
	tl := len(timeRange.Time)

	if dl == 0 || tl == 0 {
		return nil
	}

	var dateTime string
	var ttime time.Time
	var err error
	var ok bool = true
	var timeLayout = "2006.01.02 15:04"
	var list []int

	loc, _ := time.LoadLocation("Local")

	for _, d := range timeRange.Date {
		for _, t := range timeRange.Time {
			dateTime = fmt.Sprintf("%s %s", d.Start, t.Start)
			ttime, err = time.ParseInLocation(timeLayout, dateTime, loc)
			if err != nil {
				ok = false
				goto _EXIT_FUNC_
			}

			list = append(list, int(ttime.Unix()))

			dateTime = fmt.Sprintf("%s %s", d.Start, t.End)
			ttime, err = time.ParseInLocation(timeLayout, dateTime, loc)
			if err != nil {
				ok = false
				goto _EXIT_FUNC_
			}

			list = append(list, int(ttime.Unix()))

			dateTime = fmt.Sprintf("%s %s", d.End, t.Start)
			ttime, err = time.ParseInLocation(timeLayout, dateTime, loc)
			if err != nil {
				ok = false
				goto _EXIT_FUNC_
			}

			list = append(list, int(ttime.Unix()))

			dateTime = fmt.Sprintf("%s %s", d.End, t.End)
			ttime, err = time.ParseInLocation(timeLayout, dateTime, loc)
			if err != nil {
				ok = false
				goto _EXIT_FUNC_
			}

			list = append(list, int(ttime.Unix()))
		}
	}

_EXIT_FUNC_:

	if !ok {
		return nil
	}

	if len(list) < 2 {
		return nil
	}

	sort.Ints(list)

	return list
}

/*
 *@note 获取开始时间和结束时间
 *@param timeRange: PCQkCouponTimeRanges
 *@return (int64, int64, bool): (开始时间, 结束时间, 成功或失败)
 */
func GetStartAndEndTick(timeRange *models.PCQkCouponTimeRanges) (int64, int64, bool) {
	if timeRange == nil {
		return 0, 0, false
	}

	list := getSortTimeRangeList(timeRange)
	if list == nil {
		return 0, 0, false
	}

	return int64(list[0]), int64(list[len(list)-1]), true
}

/*
1.优惠券可用日期范围显示规则：
a.后台根据网络请求时间戳，获取当前日期date,当前time
b.如果有多个可用日期范围，如(a,b),(c,d);
  if(date < a)
     return (a,b);
  if( a<=date<=b )
	 return (a,b);
  if (b<date<c)
     return (c,d);
  if (c<＝date<＝d)
	 return (c,d);
  if (date>d) //已过期
	 return (c,d);
2.优惠券可用时间范围显示规则：判断逻辑同上

 *@note 获取返回给客户端显示的时间
 *@param timeRange: PCQkCouponTimeRanges
 *@return *PCQkCouponTimeRange
*/
func GetClientShowDateTime(timeRange *models.PCQkCouponTimeRanges) *models.PCQkCouponTimeRange {
	if timeRange == nil {
		return nil
	}

	//log.Debugf("PCQkCouponTimeRanges:%v", timeRange)

	dl := len(timeRange.Date)
	tl := len(timeRange.Time)

	if dl == 0 || tl == 0 {
		return nil
	}

	var err error
	var date_list []int
	var time_list []int

	for _, d := range timeRange.Date {
		var dd int

		dd, err = utility.ToInt(strings.Replace(d.Start, ".", "", -1))
		if err != nil {
			continue
		}

		date_list = append(date_list, dd)

		dd, err = utility.ToInt(strings.Replace(d.End, ".", "", -1))
		if err != nil {
			continue
		}

		date_list = append(date_list, dd)
	}

	sort.Ints(date_list)

	for _, t := range timeRange.Time {
		var tt int

		tt, err = utility.ToInt(strings.Replace(t.Start, ":", "", -1))
		if err != nil {
			continue
		}

		time_list = append(time_list, tt)

		tt, err = utility.ToInt(strings.Replace(t.End, ":", "", -1))
		if err != nil {
			continue
		}

		time_list = append(time_list, tt)
	}

	sort.Ints(time_list)

	var start int
	var end int

	cur_date, _ := utility.ToInt(time.Now().Format("20060102"))
	cur_time, _ := utility.ToInt(time.Now().Format("1504"))

	tr := &models.PCQkCouponTimeRange{
		Date: &models.PCQkCouponDataRange{},
		Time: &models.PCQkCouponDataRange{},
	}

	llen := len(date_list)

	for i := 0; i < llen; i = i + 2 {
		if i == 0 && date_list[i] > cur_date {
			start = date_list[i]
			end = date_list[i+1]
			break
		}

		if date_list[i] <= cur_date && date_list[i+1] >= cur_date {
			start = date_list[i]
			end = date_list[i+1]
			break
		}

		if i != 0 && date_list[i] > cur_date && date_list[i-1] < cur_date {
			start = date_list[i]
			end = date_list[i+1]
			break
		}

		if date_list[llen-1] < cur_date {
			start = date_list[llen-2]
			end = date_list[llen-1]
			break
		}
	}

	if start != 0 && end != 0 {
		start_date := utility.ToString(start)
		end_date := utility.ToString(end)
		if len(start_date) != 8 || len(end_date) != 8 {
			return nil
		}

		tr.Date.Start = start_date[:4] + "." + start_date[4:6] + "." + start_date[6:8]
		tr.Date.End = end_date[:4] + "." + end_date[4:6] + "." + end_date[6:8]
		start = 0
		end = 0
	} else {
		return nil
	}

	llen = len(time_list)

	for i := 0; i < llen; i = i + 2 {
		if i == 0 && time_list[0] > cur_time {
			start = time_list[i]
			end = time_list[i+1]
			break
		}

		if time_list[i] <= cur_time && time_list[i+1] >= cur_time {
			start = time_list[i]
			end = time_list[i+1]
			break
		}

		if i != 0 && time_list[i] > cur_time && time_list[i-1] < cur_time {
			start = time_list[i]
			end = time_list[i+1]
			break
		}

		if time_list[llen-1] < cur_time {
			start = time_list[llen-2]
			end = time_list[llen-1]
			break
		}
	}

	fmt.Println(start)
	fmt.Println(end)

	if start != 0 || end != 0 {
		start_time := utility.ToString(start)
		end_time := utility.ToString(end)

		if len(start_time) == 1 {
			tr.Time.Start = "00:0" + start_time[:1]
		} else if len(start_time) == 2 {
			tr.Time.Start = "00:" + start_time[:2]
		} else if len(start_time) == 3 {
			tr.Time.Start = "0" + start_time[:1] + ":" + start_time[1:3]
		} else if len(start_time) == 4 {
			tr.Time.Start = start_time[:2] + ":" + start_time[2:4]
		} else {
			tr.Time.Start = "00:00"
		}

		if len(end_time) == 1 {
			tr.Time.End = "00:0" + end_time[:1]
		} else if len(end_time) == 2 {
			tr.Time.End = "00:" + end_time[:2]
		} else if len(end_time) == 3 {
			tr.Time.End = "0" + end_time[:1] + ":" + end_time[1:3]
		} else if len(end_time) == 4 {
			tr.Time.End = end_time[:2] + ":" + end_time[2:4]
		} else {
			tr.Time.Start = "00:00"
		}
	} else {
		tr.Time.Start = "00:00"
		tr.Time.End = "00:00"
	}

	return tr
}

func GetClientShowDateTime2(startTick int64, endTick int64) *models.PCQkCouponTimeRange {
	tr := &models.PCQkCouponTimeRange{
		Date: &models.PCQkCouponDataRange{},
		Time: &models.PCQkCouponDataRange{},
	}

	startTm := time.Unix(startTick, 0)
	endTm := time.Unix(endTick, 0)

	tr.Date.Start = startTm.Format("2006.01.02")
	tr.Date.End = endTm.Format("2006.01.02")
	tr.Time.Start = startTm.Format("15:04")
	tr.Time.End = endTm.Format("15:04")

	return tr
}

/*
 *@note 创建时，检测时间范围
 *@param timeRange: PCQkCouponTimeRanges
 *@return bool: 成功或失败
 */
func CheckCreateTimeRange(timeRange *models.PCQkCouponTimeRanges) bool {
	if timeRange == nil {
		return false
	}

	dl := len(timeRange.Date)
	tl := len(timeRange.Time)

	if dl == 0 || tl == 0 {
		return false
	}

	curDate, _ := utility.ToInt(time.Now().Format("20060102"))
	curTime, _ := utility.ToInt(time.Now().Format("1504"))

	for _, d := range timeRange.Date {
		startDate, err := utility.ToInt(strings.Replace(d.Start, ".", "", -1))
		if err != nil {
			return false
		}

		endDate, err := utility.ToInt(strings.Replace(d.End, ".", "", -1))
		if err != nil {
			return false
		}

		if startDate < curDate {
			return false
		}

		if endDate < curDate {
			return false
		}

		if startDate > endDate {
			return false
		}
	}

	for _, t := range timeRange.Time {
		startTime, err := utility.ToInt(strings.Replace(t.Start, ":", "", -1))
		if err != nil {
			return false
		}

		endTime, err := utility.ToInt(strings.Replace(t.End, ":", "", -1))
		if err != nil {
			return false
		}

		if startTime < 0 || endTime <= 0 {
			return false
		}

		if startTime > 2359 || endTime > 2359 {
			return false
		}

		if startTime >= endTime {
			return false
		}

		if curTime > endTime {
			return false
		}
	}

	return true
}

/*
 *@note 检测时间范围
 *@param startTick: 开始时间
 *@param endTick: 结束时间
 *@return bool: true:在范围内，false:不在范围内
 */
func CheckStartTime2EndTime(startTick int64, endTick int64) bool {
	curTick := time.Now().Unix()
	if startTick < curTick && endTick > curTick {
		return true
	}

	return false
}

/*
 *@note 获取时，检测时间范围
 *@param timeRange: PCQkCouponTimeRanges
 *@return bool: true:在范围内，false:不在范围内
 */
func CheckGetTimeRange(timeRange *models.PCQkCouponTimeRanges) bool {
	if timeRange == nil {
		return false
	}

	dl := len(timeRange.Date)
	tl := len(timeRange.Time)

	if dl == 0 || tl == 0 {
		return false
	}

	curDate, _ := utility.ToInt(time.Now().Format("20060102"))
	curTime, _ := utility.ToInt(time.Now().Format("1504"))

	var ok bool

	for _, d := range timeRange.Date {
		startDate, err := utility.ToInt(strings.Replace(d.Start, ".", "", -1))
		if err != nil {
			continue
		}

		endDate, err := utility.ToInt(strings.Replace(d.End, ".", "", -1))
		if err != nil {
			continue
		}

		if startDate > curDate {
			continue
		}

		if curDate > endDate {
			continue
		}

		ok = true
	}

	if !ok {
		return false
	}

	ok = false

	for _, t := range timeRange.Time {
		startTime, err := utility.ToInt(strings.Replace(t.Start, ":", "", -1))
		if err != nil {
			continue
		}

		endTime, err := utility.ToInt(strings.Replace(t.End, ":", "", -1))
		if err != nil {
			continue
		}

		if curTime < startTime {
			continue
		}

		if curTime > endTime {
			continue
		}

		ok = true
	}

	return ok
}

func Lmode2Str(lmode int32) string {
	str := "全模式"

	if lmode == 1 {
		str = "标准洗模式"
	} else if lmode == 2 {
		str = "快速洗模式"
	} else if lmode == 3 {
		str = "强力洗模式"
	} else if lmode == 4 {
		str = "单脱水模式"
	} else if lmode == 5 {
		str = "轻柔洗模式"
	}

	return str
}

func Utype2Str(utype int32) string {
	str := "全部用户"

	if utype == 0 {
		str = "系统"
	} else if utype == 1 {
		str = "新用户注册"
	} else if utype == 2 {
		str = "指定手机用户"
	} else if utype == 3 {
		str = "分享领取"
	} else if utype == 4 {
		str = "新手福利"
	} else if utype == 5 {
		str = "邀请好友洗衣赠送"
	} else if utype == 6 {
		str = "兑换码兑换"
	}

	return str
}

// CheckExchangeText 用正则表达式匹配4-12位的数字字母和汉字
func CheckExchangeText(text string) bool {
	reg, _ := regexp.Compile(`^[a-zA-Z0-9\p{Han}]{4,12}$`)
	return reg.MatchString(text)
}
